package com.harmony.pilot.data.service;

import com.harmony.pilot.common.dto.ASTSymbol;
import com.harmony.pilot.data.dto.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 增强的CodeQL服务
 * 支持自定义查询、AST结果解析等
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EnhancedCodeQLService {
    
    private final CodeQLQueryManager queryManager;
    
    @Value("${codeql.database-path}")
    private String databasePath;
    
    @Value("${codeql.cli-path:codeql}")
    private String cliPath;
    
    @Value("${codeql.query-timeout:60}")
    private int defaultQueryTimeout;
    
    /**
     * 执行自定义查询
     */
    public CodeQLResult executeQuery(CodeQLQueryRequest request) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 获取查询内容
            String queryId = request.getQueryFile();
            String queryContent = queryManager.getQuery(queryId);
            
            if (queryContent == null) {
                return createErrorResult(queryId, "Query not found: " + queryId);
            }
            
            // 2. 替换参数（如果有）
            String finalQuery = replaceParameters(queryContent, request.getParameters());
            
            // 3. 执行查询
            String format = request.getFormat() != null ? request.getFormat() : "json";
            int timeout = request.getTimeout() != null ? request.getTimeout() : defaultQueryTimeout;
            
            String result = executeCodeQLQuery(finalQuery, format, timeout);
            
            // 4. 解析结果
            CodeQLResult codeQLResult = new CodeQLResult();
            codeQLResult.setQueryId(queryId);
            codeQLResult.setQueryName(queryManager.getQueryInfo(queryId).getName());
            codeQLResult.setFormat(format);
            codeQLResult.setSuccess(true);
            codeQLResult.setExecutionTime(System.currentTimeMillis() - startTime);
            
            if ("json".equals(format)) {
                codeQLResult.setJsonResults(parseJsonResults(result));
            } else {
                codeQLResult.setCsvResults(result);
            }
            
            codeQLResult.setCount("json".equals(format) ? 
                codeQLResult.getJsonResults().size() : 
                countCsvLines(result));
            
            return codeQLResult;
            
        } catch (Exception e) {
            log.error("Failed to execute CodeQL query: {}", request.getQueryFile(), e);
            return createErrorResult(request.getQueryFile(), e.getMessage());
        }
    }
    
    /**
     * 查询符号（AST增强版）
     */
    @Cacheable(value = "codeql-symbols", key = "#request.symbol + ':' + #request.context.filePath")
    public List<ASTSymbol> querySymbolsAST(SymbolQueryRequest request) {
        log.info("Querying symbols with AST: symbol={}", request.getSymbol());
        
        List<ASTSymbol> symbols = new ArrayList<>();
        
        try {
            if (!isDatabaseAvailable()) {
                log.warn("CodeQL database not available");
                return symbols;
            }
            
            // 构建AST查询（使用CodeQL标准查询）
            String query = buildASTSymbolQuery(request);
            
            // 执行查询
            String result = executeCodeQLQuery(query, "json", defaultQueryTimeout);
            
            // 解析为AST符号
            symbols = parseASTSymbols(result, request);
            
            // 过滤类型
            if (request.getTypes() != null && !request.getTypes().isEmpty()) {
                symbols = symbols.stream()
                    .filter(s -> request.getTypes().contains(s.getType()))
                    .collect(Collectors.toList());
            }
            
            // 限制结果数
            if (symbols.size() > request.getMaxResults()) {
                symbols = symbols.subList(0, request.getMaxResults());
            }
            
            log.info("Found {} AST symbols", symbols.size());
            
        } catch (Exception e) {
            log.error("Failed to query symbols with AST", e);
        }
        
        return symbols;
    }
    
    /**
     * 构建AST符号查询
     */
    private String buildASTSymbolQuery(SymbolQueryRequest request) {
        StringBuilder query = new StringBuilder();
        query.append("import cpp\n\n");
        
        // 查询函数
        query.append("from Function f\n");
        query.append("where f.getName().matches(\"%").append(request.getSymbol()).append("%\")\n");
        
        // 如果提供了文件路径，添加文件过滤
        if (request.getContext() != null && request.getContext().getFilePath() != null) {
            query.append("  and f.getFile().getRelativePath().matches(\"%")
                 .append(escapeQueryString(request.getContext().getFilePath()))
                 .append("%\")\n");
        }
        
        query.append("select f.getName() as name, \"Function\" as type,\n");
        query.append("  f.getQualifiedName() as qualifiedName,\n");
        query.append("  f.getType() as returnType,\n");
        query.append("  f.getParameters() as parameters,\n");
        query.append("  f.getLocation().getStartLine() as line,\n");
        query.append("  f.getLocation().getStartColumn() as column,\n");
        query.append("  f.getFile().getRelativePath() as filePath\n");
        
        return query.toString();
    }
    
    /**
     * 解析AST符号结果
     */
    private List<ASTSymbol> parseASTSymbols(String jsonResult, SymbolQueryRequest request) {
        List<ASTSymbol> symbols = new ArrayList<>();
        
        try {
            // 简化的JSON解析（实际应该使用Jackson或其他JSON库）
            // 这里假设CodeQL返回的是JSON数组，每个元素是一个对象
            // 实际使用时需要根据CodeQL的JSON格式进行调整
            
            // 示例解析逻辑（需要根据实际CodeQL输出格式调整）
            String[] lines = jsonResult.split("\n");
            for (String line : lines) {
                if (line.trim().isEmpty() || line.startsWith("#") || line.startsWith("[")) {
                    continue;
                }
                
                // 简单的CSV解析（CodeQL默认输出CSV）
                // 实际应该使用JSON解析器
                ASTSymbol symbol = parseSymbolFromLine(line);
                if (symbol != null) {
                    symbols.add(symbol);
                }
            }
            
        } catch (Exception e) {
            log.error("Failed to parse AST symbols", e);
        }
        
        return symbols;
    }
    
    /**
     * 从CSV行解析符号（临时实现，实际应该解析JSON）
     */
    private ASTSymbol parseSymbolFromLine(String line) {
        try {
            String[] parts = line.split("\\|");
            if (parts.length >= 3) {
                ASTSymbol symbol = new ASTSymbol();
                symbol.setName(parts[0].trim());
                symbol.setType(parts.length > 1 ? parts[1].trim() : "Unknown");
                symbol.setQualifiedName(parts.length > 2 ? parts[2].trim() : symbol.getName());
                return symbol;
            }
        } catch (Exception e) {
            log.debug("Failed to parse line: {}", line, e);
        }
        return null;
    }
    
    /**
     * 执行CodeQL查询
     */
    private String executeCodeQLQuery(String query, String format, int timeout) throws IOException, InterruptedException {
        // 创建临时查询文件
        File queryFile = File.createTempFile("codeql-query-", ".ql");
        queryFile.deleteOnExit();
        Files.writeString(queryFile.toPath(), query);
        
        // 构建命令
        List<String> command = new ArrayList<>();
        command.add(cliPath);
        command.add("query");
        command.add("run");
        command.add("--database=" + databasePath);
        command.add("--timeout=" + timeout);
        
        if ("json".equals(format)) {
            command.add("--format=json");
        }
        
        command.add(queryFile.getAbsolutePath());
        
        ProcessBuilder pb = new ProcessBuilder(command);
        pb.redirectErrorStream(true);
        
        Process process = pb.start();
        
        // 读取输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }
        }
        
        // 等待执行完成
        boolean finished = process.waitFor(timeout, java.util.concurrent.TimeUnit.SECONDS);
        if (!finished) {
            process.destroyForcibly();
            throw new IOException("Query timeout after " + timeout + " seconds");
        }
        
        int exitCode = process.exitValue();
        if (exitCode != 0) {
            throw new IOException("CodeQL query failed with exit code: " + exitCode);
        }
        
        return output.toString();
    }
    
    /**
     * 替换查询参数
     */
    private String replaceParameters(String query, Map<String, String> parameters) {
        if (parameters == null || parameters.isEmpty()) {
            return query;
        }
        
        String result = query;
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            String placeholder = "${" + entry.getKey() + "}";
            result = result.replace(placeholder, escapeQueryString(entry.getValue()));
        }
        return result;
    }
    
    /**
     * 转义查询字符串
     */
    private String escapeQueryString(String value) {
        if (value == null) {
            return "";
        }
        // CodeQL字符串转义
        return value.replace("\"", "\\\"");
    }
    
    /**
     * 解析JSON结果
     */
    private List<Map<String, Object>> parseJsonResults(String jsonResult) {
        // TODO: 使用Jackson或其他JSON库解析
        // 这里返回空列表，实际需要根据CodeQL的JSON格式实现
        return new ArrayList<>();
    }
    
    /**
     * 统计CSV行数
     */
    private int countCsvLines(String csvResult) {
        return csvResult.split("\n").length;
    }
    
    /**
     * 检查数据库是否可用
     */
    private boolean isDatabaseAvailable() {
        File dbDir = new File(databasePath);
        return dbDir.exists() && dbDir.isDirectory();
    }
    
    /**
     * 创建错误结果
     */
    private CodeQLResult createErrorResult(String queryId, String error) {
        CodeQLResult result = new CodeQLResult();
        result.setQueryId(queryId);
        result.setSuccess(false);
        result.setError(error);
        result.setCount(0);
        return result;
    }
}

